package cn.jn.lhm.netty.part08.chat.handler;

import cn.jn.lhm.netty.part08.chat.message.RpcRequestMessage;
import cn.jn.lhm.netty.part08.chat.message.RpcResponseMessage;
import cn.jn.lhm.netty.part08.chat.service.ServicesFactory;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lhm 2753914576@qq.com
 * @time 2023/11/2 - 23:06
 **/
@Slf4j
public class RpcHandler extends ChannelInboundHandlerAdapter {

    public static final Map<Integer, Promise<Object>> RESULT_MAP = new ConcurrentHashMap<>();

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof RpcResponseMessage responseMessage) {
            log.info("收到rpc响应消息：{}", responseMessage);
            doResponse(responseMessage);
        } else if (msg instanceof RpcRequestMessage requestMessage) {
            log.info("收到rpc请求消息：{}", requestMessage);
            doRequest(ctx, requestMessage);
        } else {
            super.channelRead(ctx, msg);
        }
    }

    private void doResponse(RpcResponseMessage msg) {
        Promise<Object> promise = RESULT_MAP.remove(msg.getSequenceId());
        if (msg.getExceptionValue() == null) {
            promise.setSuccess(msg.getReturnValue());
        } else {
            promise.setFailure(msg.getExceptionValue());
        }
    }

    private void doRequest(ChannelHandlerContext ctx, RpcRequestMessage requestMessage) {
        RpcResponseMessage responseMessage = new RpcResponseMessage();
        responseMessage.setSequenceId(requestMessage.getSequenceId());
        try {
            Class<?> targetClass = Class.forName(requestMessage.getInterfaceName());
            Object instance = ServicesFactory.getService(targetClass);
            Object result = targetClass.getDeclaredMethod(requestMessage.getMethodName(), requestMessage.getParameterTypes()).invoke(instance, requestMessage.getParameterValue());
            responseMessage.setReturnValue(result);
        } catch (Exception e) {
            responseMessage.setExceptionValue(e);
        }
        ctx.writeAndFlush(responseMessage);
    }
}
